import { HttpException, HttpStatus, Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Connection, Repository, createConnection, DataSource } from "typeorm";
import * as ExcelJS from "exceljs";
import { TenantDto } from "./dto/tenant.dto";
import { SearchTenantDto } from "./dto/search-tenant.dto";
import { TenantEntity } from "./entities/tenant.entity";
import * as crypto from "crypto-js";
import { toEntity } from "src/utils/dto2Entity";
import systemConfig from "../../config/system.config";
import { PageResponseResult } from "src/common/tools/page.response.result";
import { Deleted } from "@/common/enums/deleted.enum";
import { Enabled } from "@/common/enums/enabled.enum";

/*
 *@Description: 租户管理模块业务
 *返回租户数据时，排除掉超级管理员,超级管理员id为0，默认管理员租户名为administrator。切记
 *@Author: 土豆哥
 *@Date: 2022-11-28 22:20:27
 */
@Injectable()
export class TenantService {
  @InjectRepository(TenantEntity)
  private tenantRepository: Repository<TenantEntity>;
  private dataSources: { [key: string]: DataSource } = {};
  private connections: { [key: string]: Connection } = {};

  async getTenantDataSource(tenantId: number): Promise<DataSource> {
    if (this.dataSources[tenantId]) {
      return this.dataSources[tenantId];
    }

    const entity = await this.getById(tenantId);
    console.log("getTenantConnection", entity);
    const dataSource = new DataSource({
      name: tenantId.toString(),
      type: "mysql",
      host: entity.dbHost,
      port: entity.dbPort,
      username: entity.dbUsername,
      password: entity.dbPassword,
      database: entity.dbName,
      entities: [__dirname + "/../**/*.entity{.ts,.js}"],
      synchronize: false,
      // timezone: "+08:00",
      extra: {
        connectionLimit: 10,
      },
    });
    dataSource.initialize();
    this.dataSources[tenantId] = dataSource;
    return dataSource;
  }
  async getTenantConnection(tenantId: number): Promise<Connection> {
    if (this.dataSources[tenantId]) {
      return this.dataSources[tenantId];
    }
    console.log("租户id", tenantId);
    const entity = await this.getById(tenantId);
    console.log("getTenantConnection", entity);
    if (!entity) {
      throw new HttpException("未找到租户信息.", HttpStatus.UNAUTHORIZED);
    }

    const connection = await createConnection({
      name: tenantId.toString() + "_" + Date.now(),
      type: "mysql",
      host: entity.dbHost,
      port: entity.dbPort,
      username: entity.dbUsername,
      password: entity.dbPassword,
      database: entity.dbName,
      entities: [__dirname + "/../**/*.entity{.ts,.js}"],
      synchronize: false,
      extra: {
        connectionLimit: 10,
      },
    });

    this.connections[tenantId] = connection;
    return connection;
  }

  /**
   * 获取租户分页列表
   * @param searchTenantDto 搜索dto
   */
  async getTenantPageList(searchTenantDto: SearchTenantDto) {
    const { page, keyword } = searchTenantDto;
    const { current, size } = page;
    const skip = (current - 1) * size;
    const queryBuilder = this.tenantRepository.createQueryBuilder("u");
    queryBuilder.where("u.id<>0");
    if (keyword) {
      queryBuilder.andWhere(`u.tenant_name=:tenantName`, {
        tenantName: keyword,
      });
      queryBuilder.orWhere(`u.phone=:phone`, { phone: keyword });
    }
    const entities = await queryBuilder
      .orderBy("u.create_time", "DESC")
      .offset(skip)
      .limit(size)
      .getMany();
    page.total = await queryBuilder.getCount();
    const result = new PageResponseResult<TenantEntity[]>(page.total, entities);
    return result;
  }

  /**
   * 获取租户列表
   */
  async getTenantList() {
    const entities = await this.tenantRepository
      .createQueryBuilder("u")
      .leftJoinAndSelect("u.roles", "system_roles")
      .where("u.id<>0")
      .getMany();
    return entities;
  }

  /**
   * 根据租户id获取租户信息
   * @param id 编号
   */
  async getTenantById(id: number) {
    const entity = await this.getById(id);
    return entity;
  }

  /**
   * 创建租户
   * @param tenantDto 租户dto
   */
  async createTenant(tenantDto: TenantDto) {
    const tenant = await this.tenantRepository.findOneBy({
      tenantCode: tenantDto.tenantCode,
    });
    if (tenant) {
      throw new HttpException(
        {
          message: "操作失败,租户编码已使用.",
        },
        HttpStatus.BAD_REQUEST
      );
    }
    const tenantEntity = new TenantEntity();
    toEntity(tenantDto, tenantEntity);
    tenantEntity.deleted = Deleted.NoDeleted;
    tenantEntity.enabled = Enabled.Enabled;
    tenantEntity.createTime = new Date();
    await this.tenantRepository.insert(tenantEntity);
  }

  /**
   * 修改租户
   * @param id 编号
   * @param tenantDto 租户dto
   */
  async updateTenantById(id: number, tenantDto: TenantDto) {
    const tenant = await this.getById(id);
    if (!tenant) {
      throw new HttpException(
        {
          message: "操作失败,未找到租户信息.",
        },
        HttpStatus.BAD_REQUEST
      );
    }
    const tenantEntity = new TenantEntity();
    toEntity(tenantDto, tenantEntity);
    await this.tenantRepository.update(id, tenantEntity);
  }

  /**
   * 删除租户
   * @param id 编号
   */
  async removeTenantById(id: number) {
    await this.tenantRepository.delete(id);
  }

  /**
   * 批量删除租户
   * @param id 编号
   */
  async removeTenantByIds(ids: string) {
    const arr = ids.split(",");
    await this.tenantRepository.delete(arr);
  }

  /**
   * 启用租户
   * @param id 编号
   */
  async enabledTenantById(id: number) {
    const tenantEntity = new TenantEntity();
    tenantEntity.enabled = Enabled.Enabled;
    await this.tenantRepository.update(id, tenantEntity);
  }

  /**
   * 禁用租户
   * @param id 编号
   */
  async disableTenantById(id: number) {
    const tenantEntity = new TenantEntity();
    tenantEntity.enabled = Enabled.Disable;
    await this.tenantRepository.update(id, tenantEntity);
  }
  private async getById(id: number) {
    return await this.tenantRepository.findOne({
      where: {
        id,
      },
    });
  }
}
